﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;

namespace Walson.Form.FlightInstrument
{

    /// <summary>
    /// 起飞点方位指示器
    /// </summary>
    public class HomeIndicator : UserControl
    {
        #region 必要的东西
        /// <summary> 
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary> 
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // VerticalSpeedInidicator
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.DoubleBuffered = true;
            this.Name = "HomeInidicator";
            this.Size = new System.Drawing.Size(90, 90);

            this.ResumeLayout(false);

        }

        #endregion
        #endregion

        private float _HomeLatitude;
        /// <summary>
        /// 起飞点纬度
        /// </summary>
        public double HomeLatitude
        {
            get
            {
                return _HomeLatitude;
            }
            set
            {
                _HomeLatitude = (float)value;
                this.Invalidate();
            }
        }

        private float _HomeLongitude;
        /// <summary>
        /// 起飞点经度
        /// </summary>
        public double HomeLongitude
        {
            get
            {
                return _HomeLongitude;
            }
            set
            {
                _HomeLongitude = (float)value;
                this.Invalidate();
            }
        }

        private float _CurrentLatitude;
        /// <summary>
        /// 当前纬度
        /// </summary>
        public double CurrentLatitude
        {
            get
            {
                return _CurrentLatitude;
            }
            set
            {
                _CurrentLatitude = (float)value;
                this.Invalidate();
            }
        }

        private float _CurrentLongitude;
        /// <summary>
        /// 当前经度
        /// </summary>
        public double CurrentLongitude
        {
            get
            {
                return _CurrentLongitude;
            }
            set
            {
                _CurrentLongitude = (float)value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// 当前位置距离起飞点的距离
        /// </summary>
        public double Distance
        {
            get
            {
                return GetDistance(_CurrentLatitude, _CurrentLongitude, _HomeLatitude, _HomeLongitude);
            }
            private set
            {

            }
        }

        /// <summary>
        /// 前景色
        /// </summary>
        public override Color ForeColor
        {
            get
            {
                return base.ForeColor;
            }
            set
            {
                base.ForeColor = value;
                _Pen = new Pen(value, 2);
                LoadResource();
                DrawElement();
                this.Invalidate();
            }

        }

        /// <summary>
        /// 背景色
        /// </summary>
        public override Color BackColor
        {
            get
            {
                return base.BackColor;
            }
            set
            {
                base.BackColor = value;
                DrawElement();
                this.Invalidate();
            }
        }

        private double _Heading;
        /// <summary>
        /// 当前的航向
        /// </summary>
        public double Heading
        {
            get
            {
                return _Heading;
            }
            set
            {
                while (_Heading > 360)
                    _Heading -= 360;
                while (_Heading < 0)
                    _Heading += 360;
                _Heading = value;
                this.Invalidate();
            }
        }

        private bool _ShowDistance;
        /// <summary>
        /// 是否显示距离
        /// </summary>
        public bool ShowDistance
        {
            get
            {
                return _ShowDistance;
            }
            set
            {
                _ShowDistance = value;
                this.Invalidate();
            }
        }

        private bool _CenterRotate;
        /// <summary>
        /// 是否中心旋转
        /// </summary>
        public bool CenterRotate
        {
            get
            {
                return _CenterRotate;
            }
            set
            {
                _CenterRotate = value;
                this.Invalidate();
            }
        }

        private Size _PlaneSize;
        private Size _OriginalSize;
        private Bitmap _Plane;
        private void LoadResource()
        {
            Assembly myAssembly = Assembly.GetExecutingAssembly();
            Stream myStream = myAssembly.GetManifestResourceStream("Walson.Resources.Plane.png");
            Bitmap bmp = new Bitmap(myStream);
            Bitmap bmp2 = new Bitmap((int)(bmp.Width * _PlaneScaleFactor), (int)(bmp.Height * _PlaneScaleFactor));


            for (int i = 0; i < bmp.Width; i++)
                for (int j = 0; j < bmp.Height; j++)
                {
                    if (bmp.GetPixel(i, j).A != 0)
                        bmp.SetPixel(i, j, base.ForeColor);
                }

            using (Graphics g = Graphics.FromImage(bmp2))
            {
                g.ScaleTransform(_PlaneScaleFactor, _PlaneScaleFactor);
                g.DrawImage(bmp, 0, 0);
                g.ResetTransform();

            }




            _Plane = bmp2;
            _PlaneSize = bmp2.Size;
            _OriginalSize = bmp.Size;
        }

        /// <summary>
        /// 指示起飞点方位
        /// </summary>
        public HomeIndicator()
        {
            InitializeComponent();
            _Pen = new Pen(base.ForeColor, 2);
            this.DoubleBuffered = true;
            _PlaneScaleFactor = 1;

            this.DoubleBuffered = true;

            LoadResource();

            this.SizeChanged += new EventHandler(FlightCompass_SizeChanged);

            this.Size = new Size(90, 90);
            this.ForeColor = Color.White;
            this.BackColor = Color.FromArgb(16, 16, 49);

            DrawElement();
        }

        private void FlightCompass_SizeChanged(object sender, EventArgs e)
        {
            int min = Math.Min(this.Width, this.Height);
            int r = -min / 2;
            DrawElement();
            try
            {
                _PlaneScaleFactor = (float)((-r - 30.0) / _OriginalSize.Width);
            }
            catch (System.Exception)
            {
                _PlaneScaleFactor = 1f;
            }

            if (_PlaneScaleFactor <= 0)
                _PlaneScaleFactor = 1f;

            LoadResource();
            this.Invalidate();
        }

        private Bitmap _bmp;
        private Pen _Pen;
        private float _PlaneScaleFactor = 1.0f;

        private const double EARTH_RADIUS = 6378137;//地球半径
        private static double rad(double d)
        {
            return d * Math.PI / 180.0;
        }

        /// <summary>
        /// 计算两座标间距离
        /// </summary>
        /// <param name="lat1">纬度1</param>
        /// <param name="lng1">经度1</param>
        /// <param name="lat2">纬度2</param>
        /// <param name="lng2">经度2</param>
        /// <returns></returns>
        private double GetDistance(double lat1, double lng1, double lat2, double lng2)
        {
            double radLat1 = rad(lat1);
            double radLat2 = rad(lat2);
            double a = radLat1 - radLat2;
            double b = rad(lng1) - rad(lng2);

            double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) +
             Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2)));
            s = s * EARTH_RADIUS;
            s = Math.Round(s * 10000) / 10000;
            return s;
        }

        private float GetAngle(double lat1, double lng1, double lat2, double lng2, double heading)
        {
            return (float)(180 + Math.Atan(Math.Abs(lng1 - lng2) / Math.Abs(lat1 - lat2)) - heading);
        }

        private void DrawElement()
        {
            int max = Math.Max(this.Width, this.Height);
            int min = Math.Min(this.Width, this.Height);
            int r = -min / 2;
            Bitmap bmp = new Bitmap(min, min);
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                g.TranslateTransform(min / 2f, min / 2f);
                g.Clear(this.BackColor);

                PointF[] line = new PointF[2];
                for (int i = 0; i < 60; i++)
                {
                    line[0] = new PointF(0, r + 10);
                    if (i == 0)
                    {
                        line[1] = new PointF(0, r + 25);
                        Font f = new Font(this.Font.FontFamily, this.Font.Size + 4, FontStyle.Bold);
                        SizeF size = g.MeasureString("H", f);
                        Rectangle rect = new Rectangle(-(int)size.Width / 2 - 1, r + 30, (int)size.Width + 1, (int)size.Height);
                        //g.FillRectangle(Brushes.Maroon, rect);
                        g.DrawRectangle(new Pen(this.ForeColor, 2), rect);
                        g.DrawString("H", f, new SolidBrush(base.ForeColor), -size.Width / 2, r + 30);



                    }
                    else if (i % 5 == 0)
                    {
                        line[1] = new PointF(0, r + 25);
                        int angle = i * 6;
                        SizeF size = g.MeasureString(angle.ToString(), this.Font);
                        g.DrawString(angle.ToString(), this.Font, new SolidBrush(base.ForeColor), -size.Width / 2, r + 30);

                    }
                    else
                    {
                        line[1] = new PointF(0, r + 20);
                    }
                    g.DrawLine(_Pen, line[0], line[1]);

                    g.RotateTransform(6);
                }
            }
            _bmp = bmp;
        }

        /// <summary>
        /// 绘制控件
        /// </summary>
        /// <param name="e">参数</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            if (_bmp == null)
                return;

            int min = Math.Min(this.Width, this.Height);
            int max = Math.Max(this.Width, this.Height);
            int r = -min / 2;

            using (Bitmap bmp = new Bitmap(this.Width, this.Height))
            {
                using (Graphics g = Graphics.FromImage(bmp))
                {
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                    g.Clear(BackColor);
                    if (_CenterRotate)
                    {
                        g.DrawImage(_bmp, 0, 0);
                        g.TranslateTransform(_bmp.Width / 2, _bmp.Height / 2);

                        float angle = GetAngle(_CurrentLatitude, _CurrentLongitude, _HomeLatitude, _HomeLongitude, _Heading);
                        if (float.IsNaN(angle))
                            angle = 0f;

                        g.RotateTransform(angle);                        // 绘制三角形
                        PointF[] triangle = new PointF[4];
                        triangle[0] = new PointF(0, 45 + r);
                        triangle[1] = new PointF(-7, 55f + r);
                        triangle[2] = new PointF(7, 55f + r);
                        triangle[3] = new PointF(0, 45 + r);
                        //g.DrawLines(Pens.White, triangle);
                        g.FillPolygon(new SolidBrush(base.ForeColor), triangle);

                        g.DrawImage(_Plane, -_Plane.Width / 2, -_Plane.Height / 2);
                    }
                    else
                    {
                        g.TranslateTransform(_bmp.Width / 2, _bmp.Height / 2);

                        float angle = GetAngle(_CurrentLatitude, _CurrentLongitude, _HomeLatitude, _HomeLongitude, _Heading);
                        if (float.IsNaN(angle))
                            angle = 0f;
                        g.RotateTransform(-angle);

                        //g.DrawImage(_bmp, -_bmp.Width / 2, -_bmp.Height / 2);
                        PointF[] line = new PointF[2];
                        for (int i = 0; i < 60; i++)
                        {
                            line[0] = new PointF(0, r + 10);

                            if (i == 0)
                            {
                                line[1] = new PointF(0, r + 25);
                                Font f = new Font(this.Font.FontFamily, this.Font.Size + 4, FontStyle.Bold);
                                SizeF size = g.MeasureString("H", f);
                                Rectangle rect0 = new Rectangle(-(int)size.Width / 2 - 1, r + 30, (int)size.Width + 1, (int)size.Height);
                                //g.FillRectangle(Brushes.Maroon, rect0);
                                g.DrawRectangle(new Pen(this.ForeColor, 2), rect0);
                                g.DrawString("H", f, new SolidBrush(base.ForeColor), -size.Width / 2, r + 30);

                            }
                            else if (i % 5 == 0)
                            {
                                line[1] = new PointF(0, r + 25);
                                int angle0 = i * 6;
                                SizeF size = g.MeasureString(angle0.ToString(), this.Font);
                                g.DrawString(angle0.ToString(), this.Font, new SolidBrush(base.ForeColor), -size.Width / 2, r + 30);

                            }
                            else
                            {
                                line[1] = new PointF(0, r + 20);
                            }
                            g.DrawLine(_Pen, line[0], line[1]);

                            g.RotateTransform(6);
                        }

                        g.ResetTransform();
                        g.TranslateTransform(_bmp.Width / 2, _bmp.Height / 2);

                        // 绘制三角形
                        PointF[] triangle = new PointF[4];
                        triangle[0] = new PointF(0, 45 + r);
                        triangle[1] = new PointF(-7, 55f + r);
                        triangle[2] = new PointF(7, 55f + r);
                        triangle[3] = new PointF(0, 45 + r);
                        //g.DrawLines(Pens.White, triangle);
                        g.FillPolygon(new SolidBrush(base.ForeColor), triangle);

                        g.DrawImage(_Plane, -_Plane.Width / 2, -_Plane.Height / 2);
                    }

                    g.ResetTransform();
                    if (_ShowDistance)
                    {
                        double distance = GetDistance(this._CurrentLatitude, this._CurrentLongitude, this._HomeLatitude, this._HomeLongitude);
                        string str;
                        if (distance < 1000)
                            str = string.Format("{0:f2} 米", distance);
                        else
                            str = string.Format("{0:f2} 千米", distance / 1000);
                        SizeF size = g.MeasureString(str, this.Font);
                        g.DrawString(str, this.Font, new SolidBrush(base.ForeColor), this.Width - size.Width - 10, this.Height - size.Height - 10);
                    }
                }
                e.Graphics.DrawImage(bmp, 0, 0);
            }

            // 绘制圆角控件
            Rectangle rect = new Rectangle(0, 0, base.Width, base.Height);
            int radius = 50;
            System.Drawing.Drawing2D.GraphicsPath roundRect = new System.Drawing.Drawing2D.GraphicsPath();
            //顶端 
            roundRect.AddLine(rect.Left + radius - 1, rect.Top - 1, rect.Right - radius, rect.Top - 1);
            //右上角 
            roundRect.AddArc(rect.Right - radius, rect.Top - 1, radius, radius, 270, 90);
            //右边 
            roundRect.AddLine(rect.Right, rect.Top + radius, rect.Right, rect.Bottom - radius);
            //右下角
            roundRect.AddArc(rect.Right - radius, rect.Bottom - radius, radius, radius, 0, 90);
            //底边 
            roundRect.AddLine(rect.Right - radius, rect.Bottom, rect.Left + radius, rect.Bottom);
            //左下角 
            roundRect.AddArc(rect.Left - 1, rect.Bottom - radius, radius, radius, 90, 90);
            //左边 
            roundRect.AddLine(rect.Left - 1, rect.Top + radius, rect.Left - 1, rect.Bottom - radius);
            //左上角 
            roundRect.AddArc(rect.Left - 1, rect.Top - 1, radius, radius, 180, 90);
            this.Region = new Region(roundRect);

            base.OnPaint(e);
        }
    }

}